package com.xzq.erp.aspect;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Aspect
@Component
@Slf4j
public class ApiOperationLogAspect {

    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 定义切面 以自定义 @ApiOperationLog 注解为切点，凡是添加 @ApiOperationLog 的方法，都会执行环绕中的代码
     */
    @Pointcut("@annotation(com.xzq.erp.aspect.ApiOperationLog)")
    private void apiOperationLog(){}

    /**
     * 环绕
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("apiOperationLog()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        // 获取方法上ApiOperationLog注解中的描述信息
        ApiOperationLog apiOperationLog = method.getAnnotation(ApiOperationLog.class);
        String description = apiOperationLog.description();

        // 获取目标类名称
        String className = joinPoint.getTarget().getClass().getName();

        // 获取请求方法参数
//        String methodParams = Arrays.stream(joinPoint.getArgs())
//                .map(Object::toString)
//                .collect(Collectors.joining(","));
        List<Object> args = Arrays.stream(joinPoint.getArgs()).collect(Collectors.toList());
        String methodParams = args.stream()
                .map(arg -> {
                    if (arg instanceof MultipartFile) {
                        MultipartFile multipartFile = (MultipartFile) arg;
                        return "文件名：" + multipartFile.getOriginalFilename();
                    } else {
                        return arg.toString();
                    }
                })
                .collect(Collectors.joining(","));
        // 创建一个唯一的请求ID，并设置到MDC中
        String requestId = UUID.randomUUID().toString();
        MDC.put("traceId", requestId);

        // 打印操作日志
        log.info("API操作开始 - [{}]: 类={}, 方法={}, 参数={}", 
                description, className, method.getName(), 
                methodParams.length() > 500 ? methodParams.substring(0, 500) + "..." : methodParams);

        // 记录开始时间
        long startTime = System.currentTimeMillis();

        try {
            // 执行目标方法
            Object result = joinPoint.proceed();
            
            // 计算耗时
            long executionTime = System.currentTimeMillis() - startTime;
            
            // 转换结果为JSON，避免过长日志，如果结果长度超过500，只取前500个字符
            String resultJson = objectMapper.writeValueAsString(result);
            String resultLog = resultJson.length() > 500 ? resultJson.substring(0, 500) + "..." : resultJson;
            
            // 记录正常响应日志
            log.info("API操作结束 - [{}]: 耗时={}ms, 响应结果={}", description, executionTime, resultLog);
            
            return result;
        } catch (Exception e) {
            // 记录异常日志
            log.error("API操作异常 - [{}]: 耗时={}ms, 异常信息={}", 
                    description, System.currentTimeMillis() - startTime, e.getMessage(), e);
            throw e;
        } finally {
            // 清除MDC中的数据
            MDC.remove("traceId");
        }
    }
}
